﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;

using SimpleIR;
using System.Diagnostics.Contracts;

namespace PInfoModel
{
	/// <summary>
	/// This class represents values on the eval stack, so they cannot have references taken to them. Note that 
	/// value types are actually represented as heap locations and thus will have an edge targeting the location.
	/// </summary>
	public struct PISNode
	{
		public readonly static PIMEdge[] EmptyTrgts = new PIMEdge[0];

		public readonly IRType SType;
		public readonly PIMEdge[] Targets;

		/// <summary>
		/// General constructor when you need to set everything.
		/// </summary>
		public PISNode(IRType stype, PIMEdge[] targets)
		{
			Contract.Requires(stype != null);
			Contract.Requires((targets != null) | (stype is IRPrimitiveType), "Must have edges unless it is a primitive type.");

			this.SType = stype;
			this.Targets = targets;
		}

		///////////////////////////////////////////////
		//Since there is no standard definitions that work well for equality or order on these 
		//we are going to spike them so that any accidental use will cause and exception

		public override string ToString()
		{
			if(this.SType is IRPrimitiveType)
			{
				IRPrimitiveType pt = (IRPrimitiveType)this.SType;
				return "[" + this.SType.ToString() + "]";
			}
			else
			{
				StringBuilder sb = new StringBuilder("[" + this.SType.ToString() + " {");

				for(int i = 0; i < this.Targets.Length; ++i)
				{
					if(i != 0)
						sb.Append(", ");
					sb.Append(this.Targets[i].ToString());
				}

				sb.Append("}]");

				return sb.ToString();
			}
		}

		internal void Serialize(PInfoSerializer sr)
		{
			sr.WriteStartTag("SNode");

			sr.WriteIRType("SType", this.SType);

			sr.WriteCollectionStartTag("Trgts", this.Targets.Length);
			for(int i = 0; i < this.Targets.Length; ++i)
				this.Targets[i].Serialize(sr);
			sr.WriteCollectionEndTag("Trgts");

			sr.WriteEndTag("SNode");
		}

		internal static PISNode Deserialize(PInfoDeSerializer dsr)
		{
			dsr.ReadStartTag("SNode");

			IRType stype = dsr.ReadIRType("SType");

			int count = dsr.ReadCollectionStartTag("Trgts");
			PIMEdge[] trgs = new PIMEdge[count];
			for(int i = 0; i < count; ++i)
				trgs[i] = PIMEdge.Deserialize(dsr);
			dsr.ReadCollectionEndTag("Trgts");

			dsr.ReadEndTag("SNode");

			return new PISNode(stype, trgs);
		}

		/// <summary>
		/// Compute the dgml representation for a stack memory node.
		/// </summary>
		internal void DGMLDumpStackNode(int stackpos, XmlWriter xmlw)
		{
			xmlw.WriteStartElement("Node");

			string locname = "eval[" + stackpos.ToString() + "]";
			xmlw.WriteAttributeString("Id", locname);
			xmlw.WriteAttributeString("Label", locname);
			xmlw.WriteAttributeString("Background", "Gold");

			xmlw.WriteAttributeString("Type", this.SType.ToString());

			xmlw.WriteEndElement();
		}

		/// <summary>
		/// Compute the dgml representation of the edges associated wiht a stack memory node.
		/// </summary>
		internal void DGMLDumpStackNodeEdges(int stackpos, XmlWriter xmlw)
		{
			string locname = "eval[" + stackpos.ToString() + "]";
			PIMEdge.DGMLDumpStackRefEdges(this.Targets, locname, xmlw);
		}
	}
}
